/*
 * Copyright 2009-2013 PrimeTek.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.onionframework.faces.export;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import javax.el.MethodExpression;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;

import org.onionframework.faces.Constants;
import org.richfaces.component.UIColumn;
import org.richfaces.component.UIDataTable;


public class CSVExporter extends Exporter {

    @Override
	public void export(FacesContext context, UIDataTable table, String filename, boolean pageOnly, boolean selectionOnly, String encodingType, MethodExpression preProcessor, MethodExpression postProcessor) throws IOException {
		ExternalContext externalContext = context.getExternalContext();
        configureResponse(externalContext, filename);
        Writer writer = externalContext.getResponseOutputWriter();
    	
    	addColumnFacets(writer, table, ColumnType.HEADER);
    	
        if(pageOnly) {
            exportPageOnly(context, table, writer);
        }
        else if(selectionOnly) {
          //  exportSelectionOnly(context, table, writer);
        }
        else {
            exportAll(context, table, writer);
        }
        
       /* if(table.hasFooterColumn()) {
            addColumnFacets(writer, table, ColumnType.FOOTER);
        }*/
            	        
        writer.flush();
        writer.close();
        
        externalContext.responseFlushBuffer();
	}
    
    protected void addColumnFacets(Writer writer, UIDataTable table, ColumnType columnType) throws IOException {
        boolean firstCellWritten = false;
        
        UIColumn col;
        for(UIComponent child : table.getChildren()) {
        	col = (UIColumn)child;
            if(!col.isRendered()) {
                continue;
            }
                        
            /*if(col instanceof DynamicColumn) {
                ((DynamicColumn) col).applyModel();
            }*/
            
            //if(col.isExportable()) {
                if(firstCellWritten) {
                    writer.write(",");
                }
                
                addColumnValue(writer, col.getFacet(columnType.facet()));
                firstCellWritten = true;
           // }
        }
	
		writer.write("\n");
    }
    
    @Override
    protected void exportCells(UIDataTable table, Object document) {
        PrintWriter writer = (PrintWriter) document;
        boolean firstCellWritten = false;
        
        UIColumn col;
        for(UIComponent child : table.getChildren()) {
        	col = (UIColumn)child;
            if(!col.isRendered()) {
                continue;
            }
                        
            /*if(col instanceof DynamicColumn) {
                ((DynamicColumn) col).applyModel();
            }*/
            
           // if(col.isExportable()) {
                if(firstCellWritten) {
                    writer.write(",");
                }
                
                try {
                    addColumnValue(writer, col.getChildren());
                } catch (IOException ex) {
                    throw new FacesException(ex);
                }
                
                firstCellWritten = true;
           // }
        }
    }
    
    protected void configureResponse(ExternalContext externalContext, String filename) {
        externalContext.setResponseContentType("text/csv");
		externalContext.setResponseHeader("Expires", "0");
		externalContext.setResponseHeader("Cache-Control","must-revalidate, post-check=0, pre-check=0");
		externalContext.setResponseHeader("Pragma", "public");
		externalContext.setResponseHeader("Content-disposition", "attachment;filename="+ filename + ".csv");
		//externalContext.addResponseCookie(Constants.DOWNLOAD_COOKIE, "true", Collections.<String, Object>emptyMap());
    }
    
	protected void addColumnValues(Writer writer, List<UIColumn> columns) throws IOException {
		for(Iterator<UIColumn> iterator = columns.iterator(); iterator.hasNext();) {
            addColumnValue(writer, iterator.next().getChildren());

            if(iterator.hasNext())
                writer.write(",");
		}
	}

	protected void addColumnValue(Writer writer, UIComponent component) throws IOException {
		String value = component == null ? "" : exportValue(FacesContext.getCurrentInstance(), component);
        
        //escape double quotes
        value = value.replaceAll("\"", "\"\"");
        
        writer.write("\"" + value + "\"");
	}
	
	protected void addColumnValue(Writer writer, List<UIComponent> components) throws IOException {
		StringBuilder builder = new StringBuilder();
		
		for(UIComponent component : components) {
			if(component.isRendered()) {
				String value = exportValue(FacesContext.getCurrentInstance(), component);

                //escape double quotes
                value = value.replaceAll("\"", "\"\"");
                
				builder.append(value);
			}
		}
		
		writer.write("\"" + builder.toString() + "\"");
	}

    @Override
    protected void postRowExport(UIDataTable table, Object document) {
        ((PrintWriter) document).write("\n");
    }
}
